home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
kbd_fix.asm
< prev
next >
Wrap
Assembly Source File
|
1984-01-28
|
13KB
|
266 lines
;------------------------------------------------------------------------------;
; KBD_FIX.COM from Socha's Toolbox by John Socha ;
; Ref: Softalk PC Nov 83 pg 117 ;
; Softalk PC Jan 84 pg 107 (corrections, incorporated below) ;
; ;
; Note that type ahead buffer can be cleared by pressing Alt and Ctrl together.;
;------------------------------------------------------------------------------;
VECTORS SEGMENT AT 0H
ORG 9H*4
KEYBOARD_INT_VECTOR LABEL DWORD
ORG 16H*4
KEYBOARD_IO_VECTOR LABEL DWORD
VECTORS ENDS
ROM_BIOS_DATA SEGMENT AT 40H
ORG 17H
KBD_FLG DB ?
ORG 1AH
ROM_BUFFER_HEAD DW ?
ROM_BUFFER_TAIL DW ?
KB_BUFFER DW 16 DUP (?)
KB_BUFFER_END LABEL WORD
ROM_BIOS_DATA ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
ORG 100H
BEGIN: JMP INIT_VECTORS ;Initialize vectors and attach to DOS
ROM_KEYBOARD_INT DD ;Address for ROM routine
ROM_KEYBOARD_IO DD
BUFFER_HEAD DW OFFSET KEYBOARD_BUFFER
BUFFER_TAIL DW OFFSET KEYBOARD_BUFFER
KEYBOARD_BUFFER DW 160 DUP (0) ;159 character buffer
KEYBOARD_BUFFER_END LABEL WORD
;-----------------------------------------------------------------;
; This procedure sends a short beep when the buffer fills. ;
;-----------------------------------------------------------------;
KB_CONTROL EQU 61H ;Control bits for keyboard (and speaker)
ERROR_BEEP PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSHF ;Save the old interrupt enable flag
CLI ;Turn off beep during interrupt
MOV BX,30 ;Number of cycles for 1/8 second tone
IN AL,KB_CONTROL
PUSH AX
START_OF_ONE_CYCLE:
AND AL,0FCH
OUT KB_CONTROL,AL
MOV CX,60 ;Delay for one half cycle
OFF_LOOP:
LOOP OFF_LOOP
OR AL,2 ;Turn on the speaker
OUT KB_CONTROL,AL
MOV CX,60 ;Delay for second half cycle
ON_LOOP:
LOOP ON_LOOP
DEC BX ;200 cycles yet
JNZ START_OF_ONE_CYCLE
POP AX ;Recover old keyboard information
OUT KB_CONTROL,AL
POPF ;Restore interrupt flag
POP CX
POP BX
POP AX
RET
ERROR_BEEP ENDP
;---------------------------------------------------------------------;
;This procedure checks the ROM keyboard buffer to see if some program ;
;tried to clear this buffer. We know it's been cleared when the ROM ;
;tail and header overlap. Normally, the new procedure below keep the ;
;dummy character, word 0, in the buffer. ;
; ;
;Uses BX,DS ;
;Writes: BUFFER_HEAD, BUFFER_TAIL, ROM_BUFFER_HEAD ;
; ROM_BUFFER_TAIL ;
;Reads: KEYBOARD_BUFFER, KB_BUFFER ;
;---------------------------------------------------------------------;
CHECK_CLEAR_BUFFER PROC NEAR
ASSUME DS:ROM_BIOS_DATA
MOV BX,ROM_BIOS_DATA ;Establish pointer to BIOS data
MOV DS,BX
CLI ;Turn off interrupts during this check
MOV BX,ROM_BUFFER_HEAD ;Check to see if buffer is cleared
CMP BX,ROM_BUFFER_TAIL ;Is the buffer empty?
JNE BUFFER_OK ;No, then everything is alright
;Yes, then clear the internal buffer
MOV BX,OFFSET KB_BUFFER ;Reset the buffer with word 0 in buffer
MOV ROM_BUFFER_HEAD,BX
ADD BX,2
MOV ROM_BUFFER_TAIL,BX
ASSUME DS:CODE_SEG
MOV BX,CS
MOV DS,BX
MOV BX,OFFSET KEYBOARD_BUFFER ;Reset internal buffer
MOV BUFFER_HEAD,BX
MOV BUFFER_TAIL,BX
BUFFER_OK:
ASSUME DS:CODE_SEG
STI ;Interrupts back on
RET
CHECK_CLEAR_BUFFER ENDP
;------------------------------------------------------------------------------;
;This procedure intercepts the keyboard interrupt and moves any new ;
;charcters to the internal, 80 character, buffer. ;
;------------------------------------------------------------------------------;
INTERCEPT_KEYBOARD_INT PROC NEAR
ASSUME DS:NOTHING
PUSH DS
PUSH SI
PUSH BX
PUSH AX
CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
PUSHF
CALL ROM_KEYBOARD_INT ;Read scan code with BIOS routines.
;------ Transfer any charcters to internal buffer
ASSUME DS:ROM_BIOS_DATA
MOV BX,ROM_BIOS_DATA
MOV DS,BX
MOV SI,BUFFER_TAIL
MOV BX,ROM_BUFFER_HEAD ;Check if real character in buffer
ADD BX,2 ;Skip over dummy character
CMP BX,OFFSET KB_BUFFER_END
JB DONT_WRAP ;No need to wrap the pointer
MOV BX,OFFSET KB_BUFFER ;Wrap the pointer
DONT_WRAP:
CMP BX,ROM_BUFFER_TAIL ;Is there a real character?
JE NO_NEW_CHARACTERS ;No, then return to caller
MOV AX,[BX] ;Yes, move character to internal buffer
MOV CS:[SI],AX
ADD SI,2 ;Move to next position
CMP SI,OFFSET KEYBOARD_BUFFER_END
JB NOT_AT_END
MOV SI,OFFSET KEYBOARD_BUFFER
NOT_AT_END:
CMP SI,BUFFER_HEAD ;Buffer overrun?
JNE WRITE_TO_BUFFER ;Yes, beef and throw out character
CALL ERROR_BEEP
JMP SHORT NOT_AT_KB_END
WRITE_TO_BUFFER:
MOV BUFFER_TAIL,SI
NOT_AT_KB_END:
MOV ROM_BUFFER_HEAD,BX
NO_NEW_CHARACTERS:
;--------- See if CTRL + ALT pushed and clear buffer if so
MOV AL,KBD_FLG ;Get status of shift keys into AL
AND AL,0CH ;Isolate Alt and Ctrl shift flags
CMP AL,0CH ;Are both the Ctrl and Alt keys down?
JNE DONT_CLEAR_BUFFER ;No, then don't clear the buffer
MOV AX,BUFFER_TAIL ;Yes, then clear the buffer
MOV BUFFER_HEAD,AX
DONT_CLEAR_BUFFER:
POP AX
POP BX
POP SI
POP DS
IRET
INTERCEPT_KEYBOARD_INT ENDP
;------------------------------------------------------------------------------;
;This procedure replaces the ROM BIOS routines for reading a character ;
;------------------------------------------------------------------------------;
INTERCEPT_KEYBOARD_IO PROC FAR
STI ;Interrupts back on
PUSH DS ;Save current DS
PUSH BX ;Save BX temporarily
CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
MOV BX,CS ;Establish pointer to data area
MOV DS,BX
OR AH,AH ;AH=0?
JZ READ_CHARACTER ;Yes, read a character
CMP AH,1 ;AH=1? **************
JZ READ_STATUS ;Yes, return the status
POP BX ;Let the ROM BIOS handle other functions
POP DS
ASSUME DS:NOTHING
JMP ROM_KEYBOARD_IO ;Call ROM BIOS for other functions
;Read the key
ASSUME DS:CODE_SEG
READ_CHARACTER: ;ASCII read
STI ;Interrupts back on during loop
NOP ;Allow an interrupt to occur
CLI ;Interrupts back off
MOV BX,BUFFER_HEAD ;Get pointer to head of buffer
CMP BX,BUFFER_TAIL ;Test end of buffer
JE READ_CHARACTER ;Loop until something in buffer
MOV AX,[BX] ;Get scan code and ASCII code
ADD BX,2 ;Move to next word in buffer
CMP BX,OFFSET KEYBOARD_BUFFER_END ;At end of buffer?
JNE SAVE_POINTER ;No, continue
MOV BX,OFFSET KEYBOARD_BUFFER ;Yes, reset to buffer start
SAVE_POINTER:
MOV BUFFER_HEAD,BX ;Store value in variable
POP BX
POP DS
IRET ;Return to caller
;------------ASCII status
READ_STATUS:
CLI ;Interrupts off
MOV BX,BUFFER_HEAD ;Get head pointer
CMP BX,BUFFER_TAIL ;If equal (ZF=1) then nothing there
MOV AX,[BX]
STI ;Interrupts back on
POP BX ;Recover registers
POP DS
RET 2 ;Throw away flags
INTERCEPT_KEYBOARD_IO ENDP
;------------------------------------------------------------------------------;
;This procedure initializes the interrupt vectors ;
;------------------------------------------------------------------------------;
INIT_VECTORS PROC NEAR
ASSUME DS:VECTORS
PUSH DS ;Save old Data Segment
MOV AX,VECTORS ;Set up the data segment for vectors
MOV DS,AX
CLI ;Don't allow interrupts
MOV AX,KEYBOARD_INT_VECTOR ;Save addresses of BIOS routines
MOV ROM_KEYBOARD_INT,AX
MOV AX,KEYBOARD_INT_VECTOR[2]
MOV ROM_KEYBOARD_INT[2],AX
;Set up new KEYBOARD_INT vector
MOV KEYBOARD_INT_VECTOR,OFFSET INTERCEPT_KEYBOARD_INT
MOV KEYBOARD_INT_VECTOR[2],CS
STI ;Allow interrupts again
;Set up keyboard IO vector
MOV AX,KEYBOARD_IO_VECTOR
MOV ROM_KEYBOARD_IO,AX
MOV AX,KEYBOARD_IO_VECTOR[2]
MOV ROM_KEYBOARD_IO[2],AX
MOV KEYBOARD_IO_VECTOR,OFFSET INTERCEPT_KEYBOARD_IO
MOV KEYBOARD_IO_VECTOR[2],CS
;Now set up the keyboard buffer, etc.
ASSUME DS:ROM_BIOS_DATA
MOV AX,ROM_BIOS_DATA
MOV DS,AX
CLI ;Don't allow interrupts
MOV BX,OFFSET KB_BUFFER
MOV ROM_BUFFER_HEAD,BX
MOV WORD PTR [BX],0
ADD BX,2
MOV ROM_BUFFER_TAIL,BX
STI ;Allow interrupts again
MOV DX,OFFSET INIT_VECTORS ;End of resident portion
INT 27H ;Terminate but stay resident
INIT_VECTORS ENDP
CODE_SEG ENDS
END BEGIN